#pragma once

class Vector3d:public CGALVector
{
public:
	enum euDisType
	{
		TYPE_2D = 2,
		TYPE_3D = 3
	};
	Vector3d() :CGALVector() {};
	
	Vector3d(CGALVector pnt) :CGALVector(pnt.x(), pnt.y(), pnt.z()) {};
	
	Vector3d(CGALPoint pnt) :CGALVector(pnt.x(), pnt.y(), pnt.z()) {};

	Vector3d(const ZMReal Xp, const ZMReal Yp, const ZMReal Zp) :CGALVector(Xp, Yp, Zp) {};
	
	~Vector3d() {};

	void SetX(const ZMReal x)
	{
		*this = Vector3d(x, y(), z());
	}

	void SetY(const ZMReal y)
	{
		*this = Vector3d(x(), y, z());
	}

	void SetZ(const ZMReal z)
	{
		*this = Vector3d(x(), y(), z);
	}
	ZMReal operator[](int iInx) const
	{
		if (iInx == 0) return x();
		else if (iInx == 1) return y();
		else if (iInx == 2) return z();
		assert(false);
		return 0;
	}

	QVector3D ToQtPnt(const euDisType& type = TYPE_3D) const
	{
		if(type == TYPE_3D)	return QVector3D(x(), y(), z());
		return QVector3D(x(), y(), 0);
	}

	CGALPoint ToCGALPnt(const euDisType& type = TYPE_3D) const
	{
		if (type == TYPE_3D)		return CGALPoint(x(), y(), z());
		return CGALPoint(x(), y(), 0);
	}

	CGALVector ToCGALVector(const euDisType& type = TYPE_3D) const
	{
		if (type == TYPE_3D)		return CGALVector(x(), y(), z());
		return CGALVector(x(), y(), 0);
	}

	ZMReal Distance(const CGALVector& pnt, const euDisType& type = TYPE_3D) const
	{
		ZMReal ret = (x() - pnt.x())*(x() - pnt.x());
		ret+= (y() - pnt.y())*(y() - pnt.y());
		if (type == TYPE_3D)
		{
			ret += (z() - pnt.z())*(z() - pnt.z());
		}
		return sqrt(ret);
	}

	Vector3d Crossed(const Vector3d& pnt)
	{
		return Vector3d(CGAL::cross_product(this->ToCGALVector(), pnt.ToCGALVector()));
	}
	void  Cross(const Vector3d& pnt)
	{
		*this =  Vector3d(CGAL::cross_product(this->ToCGALVector(), pnt.ToCGALVector()));
	}

	void Normalize()
	{
		if (squared_length() > 1e-8)
		{
			(*this) = (*this)/(sqrt(squared_length()));
		}
	}

	ZMReal Dot(const Vector3d& pnt)
	{
		return this->ToCGALVector() * pnt.ToCGALVector();
	}

	void operator+= (const Vector3d& pnt)
	{
		*this = *this + pnt;
	}

	void operator/= (const ZMReal&fValue)
	{
		*this = *this / fValue;
	}
	void operator*= (const ZMReal&fValue)
	{
		*this = *this * fValue;
	}
	void Rotate(const Vector3d& pntAxis, const Vector3d& dirAxis, const ZMReal& fAngle);

	void Rotate1(const Vector3d& pntAxis, const Vector3d& dirAxis, const ZMReal& fAngle)
	{
		Vector3d ret;
		ZMReal m[4][4], vIn[4] = { x(), y(), z(), 1 }, vOut[4];
		float a = pntAxis[0];
		float b = pntAxis[1];
		float c = pntAxis[2];
		float u = dirAxis.x();
		float v = dirAxis.y();
		float w = dirAxis.z();

		float uu = u * u;
		float uv = u * v;
		float uw = u * w;
		float vv = v * v;
		float vw = v * w;
		float ww = w * w;
		float au = a * u;
		float av = a * v;
		float aw = a * w;
		float bu = b * u;
		float bv = b * v;
		float bw = b * w;
		float cu = c * u;
		float cv = c * v;
		float cw = c * w;

		float costheta = cosf(fAngle);
		float sintheta = sinf(fAngle);

		m[0][0] = uu + (vv + ww) * costheta;
		m[0][1] = uv * (1 - costheta) + w * sintheta;
		m[0][2] = uw * (1 - costheta) - v * sintheta;
		m[0][3] = 0;

		m[1][0] = uv * (1 - costheta) - w * sintheta;
		m[1][1] = vv + (uu + ww) * costheta;
		m[1][2] = vw * (1 - costheta) + u * sintheta;
		m[1][3] = 0;

		m[2][0] = uw * (1 - costheta) + v * sintheta;
		m[2][1] = vw * (1 - costheta) - u * sintheta;
		m[2][2] = ww + (uu + vv) * costheta;
		m[2][3] = 0;

		m[3][0] = (a * (vv + ww) - u * (bv + cw)) * (1 - costheta) + (bw - cv) * sintheta;
		m[3][1] = (b * (uu + ww) - v * (au + cw)) * (1 - costheta) + (cu - aw) * sintheta;
		m[3][2] = (c * (uu + vv) - w * (au + bv)) * (1 - costheta) + (av - bu) * sintheta;
		m[3][3] = 1;

		for (int i=0; i<4; ++i)
		{
			vOut[i] = 0;
			for (int j=0; j<4; ++j)
			{
				vOut[i] += vIn[j] * m[j][i];
			}
		}
		*this = Vector3d(vOut[0], vOut[1], vOut[2]);
	}

	void Write(CSaveData& fp)  const
	{
		fp.Write(x());
		fp.Write(y());
		fp.Write(z());
	}

	int Read(CLoadData& fp)
	{
		ZMReal x, y, z;
		fp.Read(x);
		fp.Read(y);
		fp.Read(z);
		*this = Vector3d(x, y, z);
		return 0;
	}
};

class Vector2d :public CGALVector2
{
public:
	Vector2d() :CGALVector2() {};

	Vector2d(CGALVector2 pnt) :CGALVector2(pnt.x(), pnt.y()) {};
	Vector2d(CGALPoint2 pnt) :CGALVector2(pnt.x(), pnt.y()) {};


	Vector2d(const ZMReal x, const ZMReal y) :CGALVector2(x,y) {};

	~Vector2d() {};
	
	void SetX(const ZMReal x)
	{
		*this = Vector2d(x, y());
	}

	void SetY(const ZMReal y)
	{
		*this = Vector2d(x(), y);
	}
	ZMReal operator[](int iInx) const
	{
		if (iInx == 0) return x();
		else if (iInx == 1) return y();
		assert(false);
		return 0;
	}

	QVector2D ToQtPnt() const
	{
		return QVector2D(x(), y());
	}

	CGALPoint2 ToCGALPnt() const
	{
		return CGALPoint2(x(), y());
	}
	ZMReal Distance(const CGALVector2& pnt) const
	{
		ZMReal ret = (x() - pnt.x())*(x() - pnt.x());
		ret += (y() - pnt.y())*(y() - pnt.y());
		return sqrt(ret);
	}
};

#define ZMPoint3D Vector3d 
#define ZMPoint2D Vector2d 